package dy.com.第7章服务器优化.Server.handler;

import dy.com.收发并行.Util.CloseUtils;
import dy.com.第7章服务器优化.core.Connector;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ClientHandler {
    private Connector connector;
    SocketChannel socketChannel;
    private ClientHandlerCallback clientHandlerCallback;
    ClientWriteHandler clientWriteHandler;
    private final String clientInfo;

    public ClientHandler(SocketChannel socketChannel, ClientHandlerCallback clientHandlerCallback) throws IOException {
        this.socketChannel = socketChannel;

        connector =new Connector(){
            @Override
            public void onChannelCLosed(SocketChannel channel) {
                super.onChannelCLosed(channel);
                exitBySelf();
            }

            @Override
            public void onReceiveNewMessage(String str) {
                super.onReceiveNewMessage(str);
                clientHandlerCallback.onNewMessageArrived(ClientHandler.this,str);
            }
        };
        connector.setup(socketChannel);




        //注册写selector
        Selector writeSelector = Selector.open();
        socketChannel.register(writeSelector, SelectionKey.OP_WRITE);
        clientWriteHandler = new ClientWriteHandler(writeSelector);

        this.clientHandlerCallback = clientHandlerCallback;
        this.clientInfo = socketChannel.getRemoteAddress().toString();
        System.out.println("新客户端连接：" + this.clientInfo);
    }

    public String getClientInfo() {
        return clientInfo;
    }

    public void exit() {
        CloseUtils.close(connector);
        clientWriteHandler.exit();
        CloseUtils.close(socketChannel);
        System.out.println(clientInfo);
    }

    private void exitBySelf() {
        exit();
        clientHandlerCallback.onSelfClosed(this);
    }

    //接口回调
    public interface ClientHandlerCallback {
        //当自己把自己关闭后，让外面的类消除自己
        void onSelfClosed(ClientHandler clientHandler);

        void onNewMessageArrived(ClientHandler clientHandler, String msg);
    }


    public void send(String str) {
        clientWriteHandler.send(str);
    }





    //写线程
    private class ClientWriteHandler {
        private Selector selector;
        private final ByteBuffer byteBuffer;
        private boolean finish;
        private ExecutorService executorService;

        public ClientWriteHandler(Selector selector) {
            this.selector = selector;
            byteBuffer = ByteBuffer.allocate(256);
            executorService = Executors.newSingleThreadExecutor();

        }


        void send(String str) {
            if (finish) {
                return;
            }
            executorService.execute(new WriteRunnable(str));
        }

        public void exit() {
            finish = true;
            CloseUtils.close(selector);
            executorService.shutdown();
        }

        class WriteRunnable implements Runnable {
            String str;

            WriteRunnable(String str) {
                this.str = str+"\n";
            }

            @Override
            public void run() {
                if (ClientHandler.ClientWriteHandler.this.finish) {
                    return;
                }
                byteBuffer.clear();
                byteBuffer.put(str.getBytes());
                //反转，将写模式换为读模式，修改position的位置
                byteBuffer.flip();
                while (!finish && byteBuffer.hasRemaining()) {
                    try {
                        int len = socketChannel.write(byteBuffer);
                        if(len<0){
                            System.out.println("已经无法向客户端发送数据");
                            ClientHandler.this.exitBySelf();
                            break;
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }
            }
        }
    }
}
